package models

import (
	"encoding/json"
	"errors"
	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/httpmvc/model"
	dto "ssadmin/common/query"
	"ssadmin/common/utils"
	"ssadmin/internal/admin/models/query"
	"strings"
	"time"

	"gorm.io/gorm"
)

type User struct {
	UserId        string    `json:"id" gorm:"column:id;primaryKey;type:varchar(50);comment:用户ID"`
	Username      string    `json:"username" gorm:"type:varchar(50);comment:用户名"`
	Password      string    `json:"password" gorm:"type:varchar(128);comment:密码"`
	Email         string    `json:"email" gorm:"type:varchar(128);comment:邮箱"`
	Mobile        string    `json:"mobile" gorm:"type:varchar(20);comment:联系电话"`
	Status        string    `json:"status" gorm:"type:varchar(1);comment:状态 0锁定 1有效"`
	CreateTimeDts time.Time `json:"-" gorm:"type:datetime;column:create_time;comment:创建时间"`
	CreateTime    string    `json:"createTime" gorm:"-"`
	ModifyTime    time.Time `json:"modifyTime" gorm:"column:update_time;type:datetime;comment:修改时间"`
	LastLoginTime time.Time `json:"lastLoginTime" gorm:"type:datetime;comment:最近访问时间"`
	Sex           string    `json:"sex" gorm:"type:varchar(10);comment:性别 male 男 female 女 unknown 保密"`
	Description   string    `json:"description" gorm:"type:varchar(100);comment:描述"`
	Avatar        string    `json:"avatar" gorm:"type:varchar(100);comment:用户头像"`
	CreatorId     string    `json:"creatorId" gorm:"type:varchar(64);comment:CreatorId"`
	Creator       string    `json:"creator" gorm:"type:varchar(255);comment:Creator"`
	ValidDate     time.Time `json:"validDate" gorm:"type:date;comment:过期时间"`
	Company       string    `json:"company" gorm:"type:varchar(64);comment:Company"`
	Language      string    `json:"language" gorm:"type:varchar(10);comment:语言"`
	Timezone      string    `json:"timezone" gorm:"type:varchar(50);comment:时区"`
	Alias         string    `json:"alias" gorm:"type:varchar(64);comment:Alias"`
	Agency        string    `json:"agency" gorm:"type:varchar(64);comment:Agency"`
	IsAgency      string    `json:"isAgency" gorm:"type:varchar(4);comment:IsAgency"`
	OpenId        string    `json:"openId" gorm:"type:varchar(64);comment:OpenId"`
	PositionKey   string    `json:"positionKey" gorm:"type:varchar(64);comment:PositionKey"`
	DeptList      []Dept    `json:"-" gorm:"many2many:sys_user_dept_r;joinForeignKey:user_id;references:DeptId;joinReferences:dept_id;"`
	RoleList      []Role    `json:"-" gorm:"many2many:sys_user_role_r;joinForeignKey:user_id;references:RoleId;joinReferences:role_id;"`
	Goto          string    `json:"goto" gorm:"type:varchar(255);comment:goto"`
	TokenExp      int64     `json:"tokenExp"`

	DeptIdList []string `json:"-" gorm:"-"`
	DeptIds    string   `json:"deptIds" gorm:"-"`
	DeptName   string   `json:"deptName" gorm:"-"`
	//PostIds       string    `json:"postIds" gorm:"-"`
	RoleId        string `json:"roleId" gorm:"-"`
	RoleName      string `json:"roleName" gorm:"-"`
	Tenant        string `json:"-" gorm:"-"`
	Region        string `json:"region" gorm:"-"`
	Ip            string `json:"ip" gorm:"-"`
	GenerateToken string `json:"generateToken" gorm:"-"`
	model.Model
}

// GetPage 获取User列表
func (u *User) GetPage(c *query.UserQuery, list *[]User, count *int64) error {
	where := make([]func(db *gorm.DB) *gorm.DB, 0)

	if len(c.Email) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("email ilike ?", "%"+c.Email+"%")
		})
	}

	if len(c.Mobile) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("mobile ilike ?", "%"+c.Mobile+"%")
		})
	}

	if len(c.Username) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("username ilike ?", "%"+c.Username+"%")
		})
	}

	if len(c.Search) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("username ilike ?", "%"+c.Search+"%")
		})
	}

	if len(c.UsernameEq) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("username = ?", c.UsernameEq)
		})
	}

	if len(c.Status) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("status = ?", c.Status)
		})
	}

	if len(c.UserId) > 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("id in (?)", strings.Split(c.UserId, ","))
		})
	}
	if len(c.RoleId) > 0 {
		userRole := UserRole{}
		userIds := userRole.GetUserIdsByRoleId(c.RoleId)
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("id in (?)", userIds)
		})
	}

	//非admin用户，按创建人来查询
	if c.CreatorId != "1" && len(c.QueryUserId) == 0 {
		where = append(where, func(db *gorm.DB) *gorm.DB {
			return db.Where("creator_id", c.CreatorId)
		})
		//是否包含当前用户（通知的用户列表需要显示用户自己）
		if c.Self {
			where = append(where, func(db *gorm.DB) *gorm.DB {
				return db.Or("id = ?", c.CreatorId)
			})
		}
	}

	where = append(where, dto.OrderDest("create_time", true))
	where = append(where, dto.Paginate(c.GetPageSize(), c.GetPageIndex()))

	//Joins("JOIN t_user_dept ud ON ud.user_id = t_user.user_id AND ud.dept_id IN (?)", deptIds).
	err := u.Orm.Model(&User{}).Scopes(where...).Find(list).Limit(-1).Offset(-1).Count(count).Error

	ru := UserRole{}

	for i, info := range *list {
		(*list)[i].CreateTime = info.CreateTimeDts.Format(utils.TIME_FMT_FULL)
		if info.TokenExp > 0 {
			(*list)[i].GenerateToken = utils.GetCommUtil().GenServerToken(info.Username, info.TokenExp)
		}
		//获取每个用户的角色
		roleInfo := ru.GetRoleInfoByUserId(info.UserId)
		// 获取日志
		sysLog := SysLog{}
		sysLog.Orm = env.Db
		_ = sysLog.GetLatestAddressByUser(info.Username)
		(*list)[i].Region = sysLog.Region
		(*list)[i].Ip = sysLog.Ip
		(*list)[i].RoleId = roleInfo.RoleId
		(*list)[i].RoleName = roleInfo.RoleName
	}

	return err
}

// GetRecurPage 递归获取User列表
func (u *User) GetRecurPage(c *query.UserQuery, list *[]User, count *int64) error {
	sql := "WITH RECURSIVE r_user AS (\n\t" +
		"SELECT\n\t\t" +
		"sys_user.* \n\t" +
		"FROM\n\t\t" +
		"sys_user \n\t" +
		"WHERE\n\t\t" +
		"sys_user.creator_id = ? UNION ALL\n\t" +
		"SELECT\n\t\t" +
		"sys_user.* \n\t" +
		"FROM\n\t\t" +
		"sys_user,\n\t\t" +
		"r_user \n\t" +
		"WHERE\n\t\t" +
		"sys_user.creator_id = r_user.ID \n\t" +
		") SELECT\n\t" +
		"id,\n\t" +
		"username,\n\t" +
		"creator_id,\n\t" +
		"creator \nFROM\n\t" +
		"r_user \nORDER BY\n\t" +
		"creator_id"
	where := make([]func(db *gorm.DB) *gorm.DB, 0)
	where = append(where, func(db *gorm.DB) *gorm.DB {
		return db.Where("creator_id", c.CreatorId)
	})
	where = append(where, dto.OrderDest("create_time", true))
	err := u.Orm.Model(&User{}).Scopes(where...).Raw(sql, c.CreatorId).Scan(&list).Limit(-1).Offset(-1).Count(count).Error
	ru := UserRole{}
	for i, info := range *list {
		(*list)[i].CreateTime = info.CreateTimeDts.Format(utils.TIME_FMT_FULL)
		if info.TokenExp > 0 {
			(*list)[i].GenerateToken = utils.GetCommUtil().GenServerToken(info.Username, info.TokenExp)
		}
		//获取每个用户的角色
		urList := []UserRole{}
		if err = ru.FindListByConds(u.Orm, &urList, "user_id=?", info.UserId); err == nil {
			if len(urList) > 0 {
				(*list)[i].RoleId = urList[0].RoleId
			}
		}
	}
	return err
}

// GetProfile 获取User对象
func (u *User) GetProfile(c *query.UserGetReq, currentUsername string) error {
	userQuery := query.UserQuery{}
	userQuery.UserId = c.UserId
	userQuery.UsernameEq = c.Username
	where := dto.MakeCondition(userQuery)
	err := u.Orm.Model(u).Preload("RoleList").Preload("DeptList").Scopes(where).First(u).Error

	// 当前用户只能查询自己或者自己下级
	if currentUsername != "admin" && currentUsername != c.Username && u.Creator != currentUsername {
		return errors.New("当前用户无权限查询该用户")
	}

	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil
	}

	u.AfterSet()
	u.CreateTime = u.CreateTimeDts.Format(utils.TIME_FMT_FULL)
	if u.TokenExp > 0 {
		u.GenerateToken = utils.GetCommUtil().GenServerToken(u.Username, u.TokenExp)
	}
	return nil
}

func (u *User) Add(db *gorm.DB, data *User) (err error) {
	if len(data.Password) == 0 {
		data.Password = utils.NewUserDefaultPwd(data.Username)
	}
	err = db.Model(&User{}).Create(data).Error
	return err
}

func (User) Mod(db *gorm.DB, data interface{}, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	tx := db.Model(&User{}).
		Scopes(condition...).
		Updates(data)
	if tx.RowsAffected == 0 {
		return errors.New("修改失败")
	}
	return tx.Error
}

func (User) Save(db *gorm.DB, data interface{}, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	tx := db.Model(&User{}).
		Scopes(condition...).
		Save(data)
	if tx.RowsAffected == 0 {
		return errors.New("修改失败")
	}
	return tx.Error
}

func (User) ResetPassword(db *gorm.DB, username string) (err error) {
	pwd := utils.NewUserDefaultPwd(username)
	return db.Model(&User{}).Where("username = ?", username).Update("password", pwd).Error
}

//不包含用户角色与机构
func (u *User) FindBaseOne(db *gorm.DB, data *User, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	err = db.Model(&User{}).
		Scopes(
			condition...,
		).
		First(data).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil
	}
	return err
}

func (User) FindList(db *gorm.DB, data interface{}, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	err = db.Model(&User{}).
		Scopes(
			condition...,
		).Find(data).Error
	return err
}

func (User) FindPage(db *gorm.DB, data interface{}, count *int64, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	err = db.Model(&User{}).
		Scopes(condition...).
		//Joins("JOIN t_user_dept ud ON ud.user_id = t_user.user_id AND ud.dept_id IN (?)", deptIds).
		Find(data).Limit(-1).Offset(-1).
		Count(count).Error
	return err
}

func (e *User) FindOne(db *gorm.DB, data *User, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	err = db.Model(&User{}).
		Preload("RoleList").
		Scopes(
			condition...,
		).
		First(data).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil
	}
	e.RoleList = data.RoleList
	return err
}

func (User) Del(db *gorm.DB, conds string, params ...interface{}) (err error) {
	tx := db.Model(&User{}).Where(conds, params...).Delete(&User{})
	if tx.RowsAffected == 0 {
		return errors.New("修改失败")
	}
	return tx.Error
}

func (User) FindCountByConds(db *gorm.DB, count *int64, conds string, params ...interface{}) {
	db.Model(&User{}).Where(conds, params...).Find(&User{}).Count(count)
	return
}
func (User) FindListByConds(db *gorm.DB, data interface{}, conds string, params ...interface{}) (err error) {
	db.Model(&User{}).Where(conds, params...).Find(data)
	return
}

func (User) TableName() string {
	return "sys_user"
}

func (u *User) Generate() interface{} {
	o := *u
	return &o
}

func (u *User) GetId() interface{} {
	return u.UserId
}

func (u *User) AfterSet() {
	//获取用户机构id列表
	deptIds := []string{}
	deptNames := []string{}
	for _, dept := range u.DeptList {
		deptIds = append(deptIds, dept.DeptId)
		deptNames = append(deptNames, dept.DeptName)
	}
	u.DeptIdList = deptIds
	u.DeptIds = strings.Join(deptIds, ",")
	u.DeptName = strings.Join(deptNames, ",")

	//获取用户角色id列表
	roleIds := []string{}
	roleNames := []string{}
	for _, role := range u.RoleList {
		roleIds = append(roleIds, role.RoleId)
		roleNames = append(roleNames, role.RoleName)
	}
	u.RoleId = strings.Join(roleIds, ",")
	u.RoleName = strings.Join(roleNames, ",")
}

func (u User) MarshalBinary() ([]byte, error) {
	return json.Marshal(u)
}

type UserPhone struct {
	UserId   string `json:"userId"`
	UserName string `json:"username"`
	Mobile   string `json:"mobile"`
}
